#ifndef COMPOSITOR_H
#define COMPOSITOR_H

#include <queue>

#include "Widget.h"
#include "Entity.h"
#include "Vertex.h"
#include "VertexContainers.h"
#include "Texture.h"

namespace Y{

typedef std::vector< glVertex_tcnv > ComPoly;

class Compositor{
	
	public:
		struct StateData{
			std::deque<Vertex4f>	in_color;
			std::deque<Vertex3f>	in_position;
			std::deque<Texture*>	in_texture;
			
			Vertex4f in_clearColor;
			Vertex3f in_startPosition;
			Texture*	in_nullTexture;
			
			void pushColor () { in_color.push_back( in_color.back() ); }
			void pushPosition () { in_position.push_back( in_position.back() ); }
			void pushMatrix () { pushPosition(); }
			void pushTexture () { in_texture.push_back( in_texture.back() ); }
			
			void popColor () { in_color.pop_back(); }
			void popPosition () { in_position.pop_back(); }
			void popMatrix () { popPosition(); }
			void popTexture () { in_texture.pop_back(); }
			
			void pushAll () { pushColor(); pushPosition(); pushTexture(); }
			void popAll () { popColor(); popPosition(); popTexture(); }
			
			void reset () {
				in_color.clear();	in_position.clear();	in_texture.clear();
				in_color.push_back(in_clearColor);		in_position.push_back(in_startPosition);		in_texture.push_back(in_nullTexture);
			}
			
			Vertex4f& color () { return in_color.back(); }
			Vertex3f& position () { return in_position.back(); }
			Texture*& texture () { return in_texture.back(); }
			const Vertex4f& color () const { return in_color.back(); }
			const Vertex3f& position () const { return in_position.back(); }
			const Texture * texture () const { return in_texture.back(); }
		}state;
		
		struct GeometryData{
			std::vector<ComPoly>				in_polyBuffer;
			std::vector<Texture*>			in_textureBuffer;
			std::deque<ClippingPoly>		in_clippingPoly;
			
			void addPoly (const ComPoly& p,Texture *t) { in_polyBuffer.push_back(p);	in_textureBuffer.push_back(t); }
			ComPoly& startNewPoly (Texture *t) { in_polyBuffer.push_back(ComPoly());	in_textureBuffer.push_back(t);	return (in_polyBuffer.back()); }
			void pushClippingPoly () { if ( ! noClippingPoly() ){ in_clippingPoly.push_back( in_clippingPoly.back() ); } }
			void pushClippingPoly ( const ClippingPoly& p ) { in_clippingPoly.push_back( p ); }
			bool noClippingPoly () { return (in_clippingPoly.size() == 0); }
			
			void clearPolyBuffer () { in_polyBuffer.clear(); in_textureBuffer.clear(); }
			void popClippingPoly () { if ( ! noClippingPoly() ){ in_clippingPoly.pop_back(); } }
			
			void pushAll () { pushClippingPoly(); }
			void popAll () { popClippingPoly(); }
			
			ClippingPoly& clippingPoly () { return in_clippingPoly.back(); }
			ClippingPoly& previousClippingPoly () { return (in_clippingPoly[ in_clippingPoly.size() - 1 - 1 ]); }
			const ClippingPoly& clippingPoly () const { return in_clippingPoly.back(); }
			std::vector<ComPoly>& polyBuffer () { return in_polyBuffer; }
			std::vector<Texture*>& textureBuffer () { return in_textureBuffer; }
			
			
			void reset () {
				clearPolyBuffer(); in_clippingPoly.clear(); in_textureBuffer.clear();
			}
		}geometry;
		
		struct GLData{
			VertexArray< glVertex_tcnv > in_triangleBuffer;
			std::vector< glVertex_tcnv > in_tmpBuffer;
			
			void reset () { in_tmpBuffer.clear(); }
			
			VertexArray<glVertex_tcnv>& triangleBuffer () { return in_triangleBuffer; }
			std::vector<glVertex_tcnv>& tmpBuffer () { return in_tmpBuffer; }
		}gl;
		
	protected:
		StateData& S (){ return state; }
		GeometryData& G (){ return geometry; }
		
	public:
		Compositor () {}
		
		void composite ();
			void widgetSubsystem (Widget *w);
				void convertTextureCoordinates (ComPoly& p,Texture *t);
		void draw ();
		
		
};

}
#endif